// Copyright (C) 2023 即时通讯网(52im.net) & Jack Jiang.
// The RainbowChat Project. All rights reserved.
// 
// 【本产品为著作权产品，合法授权后请放心使用，禁止外传！】
// 【本次授权给：<北京小羊驼科技有限公司>，授权编号：<NT231212144350>，代码指纹：<A.702363430.550>，技术对接人微信：<ID: wxid_wbyootvkdcgj22>】
// 【授权寄送：<收件：苏先生、地址：北京市大兴区北京密码西区6号楼1单元301、电话：18613885610、邮箱：bd@huiyuanxiang-inc.com>】
// 
// 【本系列产品在国家版权局的著作权登记信息如下】：
// 1）国家版权局登记名(简称)和权证号：RainbowChat    （证书号：软著登字第1220494号、登记号：2016SR041877）
// 2）国家版权局登记名(简称)和权证号：RainbowChat-Web（证书号：软著登字第3743440号、登记号：2019SR0322683）
// 3）国家版权局登记名(简称)和权证号：RainbowAV      （证书号：软著登字第2262004号、登记号：2017SR676720）
// 4）国家版权局登记名(简称)和权证号：MobileIMSDK-Web（证书号：软著登字第2262073号、登记号：2017SR676789）
// 5）国家版权局登记名(简称)和权证号：MobileIMSDK    （证书号：软著登字第1220581号、登记号：2016SR041964）
// * 著作权所有人：江顺/苏州网际时代信息科技有限公司
// 
// 【违法或违规使用投诉和举报方式】：
// 联系邮件：jack.jiang@52im.net
// 联系微信：hellojackjiang
// 联系QQ号：413980957
// 授权说明：http://www.52im.net/thread-1115-1-1.html
// 官方社区：http://www.52im.net
package com.noober.floatmenu;


import android.app.Activity;
import android.content.Context;
import android.content.res.TypedArray;
import android.content.res.XmlResourceParser;
import android.graphics.Color;
import android.graphics.Point;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.os.Build;
import android.text.TextUtils;
import android.util.AttributeSet;
import android.util.Xml;
import android.view.Gravity;
import android.view.InflateException;
import android.view.MotionEvent;
import android.view.View;
import android.widget.LinearLayout;
import android.widget.PopupWindow;
import android.widget.TextView;

import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

//import android.support.v4.content.ContextCompat;

/**
 * Created by xiaoqi on 2017/12/11.
 */

public class FloatMenu extends PopupWindow
{

	/** Menu tag name in XML. */
	private static final String XML_MENU = "menu";

	/** Group tag name in XML. */
	private static final String XML_GROUP = "group";

	/** Item tag name in XML. */
	private static final String XML_ITEM = "item";

	private static final int ANCHORED_GRAVITY = Gravity.TOP | Gravity.START;


	private final int DEFAULT_MENU_WIDTH;
	private final int VERTICAL_OFFSET;
	private final int HORIZONAL_OFFSET;

	private Context context;
	private List<MenuItem> menuItemList;
	private View targetView;
	private Point screenPoint;
	private int clickX;
	private int clickY;
	private int menuWidth;
	private int menuHeight;
	private LinearLayout menuLayout;
	private OnItemClickListener onItemClickListener;


	public interface OnItemClickListener {
		void onClick(View v, int position);
	}

	public FloatMenu(Activity activity){
		this(activity, 0);
	}

	public FloatMenu(Activity activity, int menuWidth){
		this(activity, activity.findViewById(android.R.id.content), menuWidth);
	}

	public FloatMenu(Context context, View targetView) {
		this(context, targetView, 0);
	}

	/**
	 * 构造方法。
	 *
	 * @param context
	 * @param targetView
	 * @param menuWidth 菜单总宽度（单位：dp）
	 */
	public FloatMenu(Context context, View targetView, int menuWidth) {
		super(context);
		setOutsideTouchable(true);
		setFocusable(true);
		setBackgroundDrawable(new BitmapDrawable());
//		targetView.setOnTouchListener(new MenuTouchListener());
		setTargetView(targetView);

		this.context = context;
//		this.targetView = targetView;
		VERTICAL_OFFSET = Display.dip2px(context, -13);//-23);//10);
		HORIZONAL_OFFSET = Display.dip2px(context, 22);//20);//10);
//		DEFAULT_MENU_WIDTH = Display.dip2px(context, 180);
		DEFAULT_MENU_WIDTH = Display.dip2px(context, menuWidth > 0 ? menuWidth : 150);// 20190517 由jackjiang改！
		screenPoint = Display.getScreenMetrics(context);
		menuItemList = new ArrayList<>();
	}

	public void setTargetView(View targetView){
		if(this.targetView != null){
			this.targetView.setOnTouchListener(null);
			this.targetView = null;
		}
		if(targetView != null){
			this.targetView = targetView;
			this.targetView.setOnTouchListener(new MenuTouchListener());
		}
	}

	public void inflate(int menuRes) {
		inflate(menuRes, DEFAULT_MENU_WIDTH);
	}

	public void inflate(int menuRes, int itemWidth) {
		XmlResourceParser parser = null;
		try {
			parser = context.getResources().getLayout(menuRes);
			AttributeSet attrs = Xml.asAttributeSet(parser);
			parseMenu(parser, attrs);
		} catch (XmlPullParserException e) {
			throw new InflateException("Error inflating menu XML", e);
		} catch (IOException e) {
			throw new InflateException("Error inflating menu XML", e);
		} finally {
			if (parser != null) parser.close();
		}
		generateLayout(itemWidth);
	}

	public void items(String... items) {
		items(DEFAULT_MENU_WIDTH, items);
	}

	public void items(int itemWidth, String... items) {
		menuItemList.clear();
		for(int i=0; i < items.length; i ++){
			MenuItem menuModel = new MenuItem();
			menuModel.setItem(items[i]);
			menuItemList.add(menuModel);
		}
		generateLayout(itemWidth);
	}

	public void items(List<MenuItem> itemList) {
		menuItemList.clear();
		menuItemList.addAll(itemList);
		generateLayout(DEFAULT_MENU_WIDTH);
	}

	public void items(List<MenuItem> itemList, int itemWidth) {
		menuItemList.clear();
		menuItemList.addAll(itemList);
		generateLayout(itemWidth);
	}

	private void generateLayout(int itemWidth) {
		menuLayout = new LinearLayout(context);
		menuLayout.setBackgroundDrawable(context.getResources().getDrawable(R.drawable.floatmenu_bg_shadow_v9));
		menuLayout.setOrientation(LinearLayout.VERTICAL);
		menuLayout.setPadding(Display.dip2px(context, 24), Display.dip2px(context, 24)
				, Display.dip2px(context, 24), Display.dip2px(context, 24));

		for(int i = 0; i < menuItemList.size(); i ++){
			TextView textView = new TextView(context);
			textView.setClickable(true);
			textView.setBackgroundDrawable(context.getResources().getDrawable(R.drawable.floatmenu_item_selector));
			textView.setPadding(Display.dip2px(context, 16), Display.dip2px(context, 10)
					, Display.dip2px(context, 16), Display.dip2px(context, 10));
			textView.setWidth(itemWidth);
			textView.setGravity(Gravity.CENTER_VERTICAL | Gravity.START);
			textView.setTextSize(15);
			textView.setTextColor(Color.BLACK);
			textView.setSingleLine(true);
			textView.setEllipsize(TextUtils.TruncateAt.END);
			MenuItem menuModel = menuItemList.get(i);
			if(menuModel.getItemResId() != View.NO_ID){
				Drawable drawable = context.getResources().getDrawable(menuModel.getItemResId());
				drawable.setBounds(0, 0, drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight());
//				textView.setCompoundDrawablePadding(Display.dip2px(context, 12));
				textView.setCompoundDrawablePadding(Display.dip2px(context, 6));// 20190517 由jackjiang改！
				textView.setCompoundDrawables(drawable, null, null, null);
			}
			textView.setText(menuModel.getItem());
			if(onItemClickListener != null){
				textView.setOnClickListener(new ItemOnClickListener(i));
			}
			menuLayout.addView(textView);
		}
		int width = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED);
		int height = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED);
		menuLayout.measure(width,height);
		menuWidth = menuLayout.getMeasuredWidth();
		menuHeight = menuLayout.getMeasuredHeight();
		setContentView(menuLayout);
		setWidth(menuWidth);
		setHeight(menuHeight);

	}

	private void parseMenu(XmlPullParser parser, AttributeSet attrs) throws XmlPullParserException, IOException
    {
		int eventType = parser.getEventType();
		String tagName;
		boolean lookingForEndOfUnknownTag = false;
		String unknownTagName = null;

		// This loop will skip to the menu start tag
		do {
			if (eventType == XmlPullParser.START_TAG) {
				tagName = parser.getName();
				if (tagName.equals(XML_MENU)) {
					// Go to next tag
					eventType = parser.next();
					break;
				}
				throw new RuntimeException("Expecting menu, got " + tagName);
			}
			eventType = parser.next();
		} while (eventType != XmlPullParser.END_DOCUMENT);

		boolean reachedEndOfMenu = false;
		while (!reachedEndOfMenu) {
			switch (eventType) {
				case XmlPullParser.START_TAG:
					if (lookingForEndOfUnknownTag) {
						break;
					}
					tagName = parser.getName();
					if (tagName.equals(XML_GROUP)) {
					//	parser group
						parser.next();
					} else if (tagName.equals(XML_ITEM)) {
						readItem(attrs);
					} else if (tagName.equals(XML_MENU)) {
						// A menu start tag denotes a submenu for an item
						//pares subMenu
						parser.next();
					} else {
						lookingForEndOfUnknownTag = true;
						unknownTagName = tagName;
					}
					break;

				case XmlPullParser.END_TAG:
					tagName = parser.getName();
					if (lookingForEndOfUnknownTag && tagName.equals(unknownTagName)) {
						lookingForEndOfUnknownTag = false;
						unknownTagName = null;
					} else if (tagName.equals(XML_GROUP)) {

					} else if (tagName.equals(XML_ITEM)) {

					} else if (tagName.equals(XML_MENU)) {
						reachedEndOfMenu = true;
					}
					break;

				case XmlPullParser.END_DOCUMENT:
					throw new RuntimeException("Unexpected end of document");
			}

			eventType = parser.next();
		}
	}

	private void readItem(AttributeSet attrs) {
		TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.floatmenu_MenuItem);
		CharSequence itemTitle = a.getText(R.styleable.floatmenu_MenuItem_menu_title);
		int itemIconResId = a.getResourceId(R.styleable.floatmenu_MenuItem_icon, View.NO_ID);
		MenuItem menu = new MenuItem();
		menu.setItem(String.valueOf(itemTitle));
		if(itemIconResId != View.NO_ID){
			menu.setItemResId(itemIconResId);
		}
		menuItemList.add(menu);
		a.recycle();
	}

	private void readGroup(AttributeSet attrs) {
		TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.floatmenu_MenuItem);
		CharSequence itemTitle = a.getText(R.styleable.floatmenu_MenuItem_menu_title);
//		int itemIconResId = a.getResourceId(R.styleable.MenuItem_icon, 0);
//		menuItemList.add(String.valueOf(itemTitle));
		a.recycle();
	}

	public void show(Point point){
		clickX = point.x;
		clickY = point.y;
		show();
	}

	public void show(){
		if(isShowing()){
			return;
		}
		//it is must ,other wise 'setOutsideTouchable' will not work under Android5.0
		if(Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP){
			setBackgroundDrawable(new BitmapDrawable());
		}

		if(clickX <= screenPoint.x / 2){
			if(clickY + menuHeight < screenPoint.y){
				setAnimationStyle(R.style.floatmenu_Animation_top_left);
				showAtLocation(targetView, ANCHORED_GRAVITY, clickX +HORIZONAL_OFFSET , clickY + VERTICAL_OFFSET);
			}else {
				setAnimationStyle(R.style.floatmenu_Animation_bottom_left);
				showAtLocation(targetView, ANCHORED_GRAVITY, clickX - HORIZONAL_OFFSET, clickY - menuHeight - VERTICAL_OFFSET);
			}
		}else {
			if(clickY + menuHeight < screenPoint.y){
				setAnimationStyle(R.style.floatmenu_Animation_top_right);
				showAtLocation(targetView, ANCHORED_GRAVITY, clickX - menuWidth + HORIZONAL_OFFSET
						, clickY + VERTICAL_OFFSET);
			}else {
				setAnimationStyle(R.style.floatmenu_Animation_bottom_right);
				showAtLocation(targetView, ANCHORED_GRAVITY, clickX - menuWidth - HORIZONAL_OFFSET, clickY - menuHeight - VERTICAL_OFFSET);
			}
		}
	}

	@Override
	public void setOnDismissListener(OnDismissListener onDismissListener) {
		super.setOnDismissListener(onDismissListener);
	}

	public void setOnItemClickListener(final OnItemClickListener onItemClickListener){
		this.onItemClickListener = onItemClickListener;
		if(onItemClickListener != null){
			for (int i = 0; i < menuLayout.getChildCount(); i ++){
				View view = menuLayout.getChildAt(i);
				view.setOnClickListener(new ItemOnClickListener(i));
			}
		}
	}

	class MenuTouchListener implements View.OnTouchListener {

		@Override
		public boolean onTouch(View v, MotionEvent event) {
			if(event.getAction() == MotionEvent.ACTION_DOWN){
				clickX = (int) event.getRawX();
				clickY = (int) event.getRawY();
			}
			return false;
		}
	}

	class ItemOnClickListener implements View.OnClickListener {
		int position;

		public ItemOnClickListener(int position){
			this.position = position;
		}

		@Override
		public void onClick(View v) {
			dismiss();
			if(onItemClickListener != null){
				onItemClickListener.onClick(v, position);
			}
		}
	}
}
